#pragma once
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>

#include "../basiclib/String.h"
#include "../basiclib/Common.h"

#include <vector>
using std::vector;

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")



bool Msg( UINT message, WPARAM wParam, LPARAM lParam );

class MsgController
{
public:
	typedef bool ( *MsgFunc )( UINT msg, WPARAM wParam, LPARAM lParam );
							
							~MsgController();
	static MsgController*	Instance();
	static LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

                                                
        void                                    RegisterMsg( MsgFunc msg );
private:
                                                        MsgController(){}
                                                        MsgController( const MsgController& msgController );
        MsgController&                  operator=( const MsgController& msgController );
private:
        static  MsgController*  mMsgController;
        vector< MsgFunc >               mMsgs;
};

class Mouse
{
public:
                                                        ~Mouse();
        static Mouse*                   Instance();
        void                                    UpdateMouse( UINT message, WPARAM wParam, LPARAM lParam );

        UINT                                    X();
        UINT                                    Y();
        bool                                    IsLButtonDown() { return mLButtonDown; }
        bool                                    IsRButtonDown() { return mRButtonDown; }
private:
                                                        Mouse(){}
                                                        Mouse( const Mouse& m );
        Mouse&                                  operator=( const Mouse& m );

        static Mouse*                   mMouse;
        bool                                    mLButtonDown;
        bool                                    mRButtonDown;
        UINT                                    mX;
        UINT                                    mY;
};

class RenderFrame
{
public:
        typedef void ( *InitFunc )();
        typedef void ( *MainLoopFunc )();
        typedef void ( *UpdateFunc )( float dt );
        typedef void ( *ReleaseFunc )();

        static LPDIRECT3DDEVICE9        GetD3DDevice();
        static LPDIRECT3D9                      GetD3DObject();
        static void                                     ReleaseD3D();
                                        
                                                                RenderFrame();
        void                                            Init( HINSTANCE hInstance, String appName );
        void                                            Run();
        void                                            Release();
        void                                            Render();
        void                                            Update( float dt );

        void                                            RegisterInit( InitFunc initFunc );
        void                                            RegisterMainLoop( MainLoopFunc mainLoopFunc );
        void                                            RegisterUpdate( UpdateFunc updateFunc );
        void                                            RegisterRelease( ReleaseFunc releaseFunc );
private:
        HWND                                            InitWnd( HINSTANCE hInstance, String appName );
        void                                            InitD3D( HWND hwnd );

        void                                            OnInit();
        void                                            OnMainLoop();
        void                                            OnUpdate( float dt );
        void                                            OnRelease();
private:
        static LPDIRECT3D9                      mD3DObject;
        static LPDIRECT3DDEVICE9        mD3DDevice;

        InitFunc                                        mInitFunc;
        MainLoopFunc                            mMainLoopFunc;
        UpdateFunc                                      mUpdateFunc;
        ReleaseFunc                                     mReleaseFunc;
};